{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Implementing an LLM-powered recommendation system"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Preprocessing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>MAL_ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Score</th>\n",
       "      <th>Genres</th>\n",
       "      <th>sypnopsis</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>Cowboy Bebop</td>\n",
       "      <td>8.78</td>\n",
       "      <td>Action, Adventure, Comedy, Drama, Sci-Fi, Space</td>\n",
       "      <td>In the year 2071, humanity has colonized sever...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>5</td>\n",
       "      <td>Cowboy Bebop: Tengoku no Tobira</td>\n",
       "      <td>8.39</td>\n",
       "      <td>Action, Drama, Mystery, Sci-Fi, Space</td>\n",
       "      <td>other day, another bounty—such is the life of ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>6</td>\n",
       "      <td>Trigun</td>\n",
       "      <td>8.24</td>\n",
       "      <td>Action, Sci-Fi, Adventure, Comedy, Drama, Shounen</td>\n",
       "      <td>Vash the Stampede is the man with a $$60,000,0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>7</td>\n",
       "      <td>Witch Hunter Robin</td>\n",
       "      <td>7.27</td>\n",
       "      <td>Action, Mystery, Police, Supernatural, Drama, ...</td>\n",
       "      <td>ches are individuals with special powers like ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>Bouken Ou Beet</td>\n",
       "      <td>6.98</td>\n",
       "      <td>Adventure, Fantasy, Shounen, Supernatural</td>\n",
       "      <td>It is the dark century and the people are suff...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   MAL_ID                             Name Score  \\\n",
       "0       1                     Cowboy Bebop  8.78   \n",
       "1       5  Cowboy Bebop: Tengoku no Tobira  8.39   \n",
       "2       6                           Trigun  8.24   \n",
       "3       7               Witch Hunter Robin  7.27   \n",
       "4       8                   Bouken Ou Beet  6.98   \n",
       "\n",
       "                                              Genres  \\\n",
       "0    Action, Adventure, Comedy, Drama, Sci-Fi, Space   \n",
       "1              Action, Drama, Mystery, Sci-Fi, Space   \n",
       "2  Action, Sci-Fi, Adventure, Comedy, Drama, Shounen   \n",
       "3  Action, Mystery, Police, Supernatural, Drama, ...   \n",
       "4          Adventure, Fantasy, Shounen, Supernatural   \n",
       "\n",
       "                                           sypnopsis  \n",
       "0  In the year 2071, humanity has colonized sever...  \n",
       "1  other day, another bounty—such is the life of ...  \n",
       "2  Vash the Stampede is the man with a $$60,000,0...  \n",
       "3  ches are individuals with special powers like ...  \n",
       "4  It is the dark century and the people are suff...  "
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "anime = pd. read_csv('data/anime_with_synopsis.csv')\n",
    "anime.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "anime = anime.dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Title: Monster. Overview: Dr. Kenzou Tenma, an elite neurosurgeon recently engaged to his hospital director's daughter, is well on his way to ascending the hospital hierarchy. That is until one night, a seemingly small event changes Dr. Tenma's life forever. While preparing to perform surgery on someone, he gets a call from the hospital director telling him to switch patients and instead perform life-saving brain surgery on a famous performer. His fellow doctors, fiancée, and the hospital director applaud his accomplishment; but because of the switch, a poor immigrant worker is dead, causing Dr. Tenma to have a crisis of conscience. So when a similar situation arises, Dr. Tenma stands his ground and chooses to perform surgery on the young boy Johan Liebert instead of the town's mayor. Unfortunately, this choice leads to serious ramifications for Dr. Tenma—losing his social standing being one of them. However, with the mysterious death of the director and two other doctors, Dr. Tenma's position is restored. With no evidence to convict him, he is released and goes on to attain the position of hospital director. Nine years later when Dr. Tenma saves the life of a criminal, his past comes back to haunt him—once again, he comes face to face with the monster he operated on. He must now embark on a quest of pursuit to make amends for the havoc spread by the one he saved. Genres: Drama, Horror, Mystery, Police, Psychological, Seinen, Thriller\""
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "anime['combined_info'] = anime.apply(lambda row: f\"Title: {row['Name']}. Overview: {row['sypnopsis']} Genres: {row['Genres']}\", axis=1)\n",
    "anime['combined_info'][0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16206"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# imports\n",
    "import pandas as pd\n",
    "import tiktoken\n",
    "import os\n",
    "import openai\n",
    "\n",
    "\n",
    "\n",
    "# embedding model parameters\n",
    "embedding_model = \"text-embedding-ada-002\"\n",
    "embedding_encoding = \"cl100k_base\"  # this the encoding for text-embedding-ada-002\n",
    "max_tokens = 8000  # the maximum for text-embedding-ada-002 is 8191\n",
    "\n",
    "encoding = tiktoken.get_encoding(embedding_encoding)\n",
    "\n",
    "# omit reviews that are too long to embed\n",
    "anime[\"n_tokens\"] = anime.combined_info.apply(lambda x: len(encoding.encode(x)))\n",
    "anime = anime[anime.n_tokens <= max_tokens]\n",
    "len(anime)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>MAL_ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Score</th>\n",
       "      <th>Genres</th>\n",
       "      <th>sypnopsis</th>\n",
       "      <th>combined_info</th>\n",
       "      <th>n_tokens</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>Cowboy Bebop</td>\n",
       "      <td>8.78</td>\n",
       "      <td>Action, Adventure, Comedy, Drama, Sci-Fi, Space</td>\n",
       "      <td>In the year 2071, humanity has colonized sever...</td>\n",
       "      <td>Title: Cowboy Bebop. Overview: In the year 207...</td>\n",
       "      <td>245</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>5</td>\n",
       "      <td>Cowboy Bebop: Tengoku no Tobira</td>\n",
       "      <td>8.39</td>\n",
       "      <td>Action, Drama, Mystery, Sci-Fi, Space</td>\n",
       "      <td>other day, another bounty—such is the life of ...</td>\n",
       "      <td>Title: Cowboy Bebop: Tengoku no Tobira. Overvi...</td>\n",
       "      <td>199</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>6</td>\n",
       "      <td>Trigun</td>\n",
       "      <td>8.24</td>\n",
       "      <td>Action, Sci-Fi, Adventure, Comedy, Drama, Shounen</td>\n",
       "      <td>Vash the Stampede is the man with a $$60,000,0...</td>\n",
       "      <td>Title: Trigun. Overview: Vash the Stampede is ...</td>\n",
       "      <td>252</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>7</td>\n",
       "      <td>Witch Hunter Robin</td>\n",
       "      <td>7.27</td>\n",
       "      <td>Action, Mystery, Police, Supernatural, Drama, ...</td>\n",
       "      <td>ches are individuals with special powers like ...</td>\n",
       "      <td>Title: Witch Hunter Robin. Overview: ches are ...</td>\n",
       "      <td>125</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>Bouken Ou Beet</td>\n",
       "      <td>6.98</td>\n",
       "      <td>Adventure, Fantasy, Shounen, Supernatural</td>\n",
       "      <td>It is the dark century and the people are suff...</td>\n",
       "      <td>Title: Bouken Ou Beet. Overview: It is the dar...</td>\n",
       "      <td>188</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   MAL_ID                             Name Score  \\\n",
       "0       1                     Cowboy Bebop  8.78   \n",
       "1       5  Cowboy Bebop: Tengoku no Tobira  8.39   \n",
       "2       6                           Trigun  8.24   \n",
       "3       7               Witch Hunter Robin  7.27   \n",
       "4       8                   Bouken Ou Beet  6.98   \n",
       "\n",
       "                                              Genres  \\\n",
       "0    Action, Adventure, Comedy, Drama, Sci-Fi, Space   \n",
       "1              Action, Drama, Mystery, Sci-Fi, Space   \n",
       "2  Action, Sci-Fi, Adventure, Comedy, Drama, Shounen   \n",
       "3  Action, Mystery, Police, Supernatural, Drama, ...   \n",
       "4          Adventure, Fantasy, Shounen, Supernatural   \n",
       "\n",
       "                                           sypnopsis  \\\n",
       "0  In the year 2071, humanity has colonized sever...   \n",
       "1  other day, another bounty—such is the life of ...   \n",
       "2  Vash the Stampede is the man with a $$60,000,0...   \n",
       "3  ches are individuals with special powers like ...   \n",
       "4  It is the dark century and the people are suff...   \n",
       "\n",
       "                                       combined_info  n_tokens  \n",
       "0  Title: Cowboy Bebop. Overview: In the year 207...       245  \n",
       "1  Title: Cowboy Bebop: Tengoku no Tobira. Overvi...       199  \n",
       "2  Title: Trigun. Overview: Vash the Stampede is ...       252  \n",
       "3  Title: Witch Hunter Robin. Overview: ches are ...       125  \n",
       "4  Title: Bouken Ou Beet. Overview: It is the dar...       188  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "anime.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openai\n",
    "from openai.embeddings_utils import get_embedding\n",
    "\n",
    "openai.api_type = \"azure\"\n",
    "openai.api_key = \"xxx\"\n",
    "openai.api_base = \"xxx\"\n",
    "openai.api_version = \"2023-11-18\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# set the environment variables needed for openai package to know to reach out to azure\n",
    "import os\n",
    "\n",
    "os.environ[\"OPENAI_API_TYPE\"] = \"azure\"\n",
    "os.environ[\"OPENAI_API_BASE\"] = \"xxx\"\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"your AzureOpenAI key\"\n",
    "os.environ[\"OPENAI_API_VERSION\"] = \"2023-11-18\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>MAL_ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Score</th>\n",
       "      <th>Genres</th>\n",
       "      <th>sypnopsis</th>\n",
       "      <th>combined_info</th>\n",
       "      <th>n_tokens</th>\n",
       "      <th>embedding</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>Cowboy Bebop</td>\n",
       "      <td>8.78</td>\n",
       "      <td>Action, Adventure, Comedy, Drama, Sci-Fi, Space</td>\n",
       "      <td>In the year 2071, humanity has colonized sever...</td>\n",
       "      <td>Title: Cowboy Bebop. Overview: In the year 207...</td>\n",
       "      <td>245</td>\n",
       "      <td>[0.00921056978404522, -0.012633174657821655, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>5</td>\n",
       "      <td>Cowboy Bebop: Tengoku no Tobira</td>\n",
       "      <td>8.39</td>\n",
       "      <td>Action, Drama, Mystery, Sci-Fi, Space</td>\n",
       "      <td>other day, another bounty—such is the life of ...</td>\n",
       "      <td>Title: Cowboy Bebop: Tengoku no Tobira. Overvi...</td>\n",
       "      <td>199</td>\n",
       "      <td>[-0.008109764195978642, -0.028518257662653923,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>6</td>\n",
       "      <td>Trigun</td>\n",
       "      <td>8.24</td>\n",
       "      <td>Action, Sci-Fi, Adventure, Comedy, Drama, Shounen</td>\n",
       "      <td>Vash the Stampede is the man with a $$60,000,0...</td>\n",
       "      <td>Title: Trigun. Overview: Vash the Stampede is ...</td>\n",
       "      <td>252</td>\n",
       "      <td>[0.0019446373917162418, -0.001545737381093204,...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>7</td>\n",
       "      <td>Witch Hunter Robin</td>\n",
       "      <td>7.27</td>\n",
       "      <td>Action, Mystery, Police, Supernatural, Drama, ...</td>\n",
       "      <td>ches are individuals with special powers like ...</td>\n",
       "      <td>Title: Witch Hunter Robin. Overview: ches are ...</td>\n",
       "      <td>125</td>\n",
       "      <td>[-0.014938411302864552, 0.007340028416365385, ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>8</td>\n",
       "      <td>Bouken Ou Beet</td>\n",
       "      <td>6.98</td>\n",
       "      <td>Adventure, Fantasy, Shounen, Supernatural</td>\n",
       "      <td>It is the dark century and the people are suff...</td>\n",
       "      <td>Title: Bouken Ou Beet. Overview: It is the dar...</td>\n",
       "      <td>188</td>\n",
       "      <td>[0.010889030061662197, 0.0069219209253787994, ...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   MAL_ID                             Name Score  \\\n",
       "0       1                     Cowboy Bebop  8.78   \n",
       "1       5  Cowboy Bebop: Tengoku no Tobira  8.39   \n",
       "2       6                           Trigun  8.24   \n",
       "3       7               Witch Hunter Robin  7.27   \n",
       "4       8                   Bouken Ou Beet  6.98   \n",
       "\n",
       "                                              Genres  \\\n",
       "0    Action, Adventure, Comedy, Drama, Sci-Fi, Space   \n",
       "1              Action, Drama, Mystery, Sci-Fi, Space   \n",
       "2  Action, Sci-Fi, Adventure, Comedy, Drama, Shounen   \n",
       "3  Action, Mystery, Police, Supernatural, Drama, ...   \n",
       "4          Adventure, Fantasy, Shounen, Supernatural   \n",
       "\n",
       "                                           sypnopsis  \\\n",
       "0  In the year 2071, humanity has colonized sever...   \n",
       "1  other day, another bounty—such is the life of ...   \n",
       "2  Vash the Stampede is the man with a $$60,000,0...   \n",
       "3  ches are individuals with special powers like ...   \n",
       "4  It is the dark century and the people are suff...   \n",
       "\n",
       "                                       combined_info  n_tokens  \\\n",
       "0  Title: Cowboy Bebop. Overview: In the year 207...       245   \n",
       "1  Title: Cowboy Bebop: Tengoku no Tobira. Overvi...       199   \n",
       "2  Title: Trigun. Overview: Vash the Stampede is ...       252   \n",
       "3  Title: Witch Hunter Robin. Overview: ches are ...       125   \n",
       "4  Title: Bouken Ou Beet. Overview: It is the dar...       188   \n",
       "\n",
       "                                           embedding  \n",
       "0  [0.00921056978404522, -0.012633174657821655, 0...  \n",
       "1  [-0.008109764195978642, -0.028518257662653923,...  \n",
       "2  [0.0019446373917162418, -0.001545737381093204,...  \n",
       "3  [-0.014938411302864552, 0.007340028416365385, ...  \n",
       "4  [0.010889030061662197, 0.0069219209253787994, ...  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "anime[\"embedding\"] = anime.combined_info.apply(lambda x: get_embedding(x, engine=embedding_model))\n",
    "anime.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "anime.rename(columns = {'embedding': 'vector'}, inplace = True)\n",
    "anime.rename(columns = {'combined_info': 'text'}, inplace = True)\n",
    "anime.to_pickle('data/anime.pkl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Start working with LLMs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.vectorstores import LanceDB"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>MAL_ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Score</th>\n",
       "      <th>Genres</th>\n",
       "      <th>sypnopsis</th>\n",
       "      <th>text</th>\n",
       "      <th>n_tokens</th>\n",
       "      <th>vector</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>Cowboy Bebop</td>\n",
       "      <td>8.78</td>\n",
       "      <td>Action, Adventure, Comedy, Drama, Sci-Fi, Space</td>\n",
       "      <td>In the year 2071, humanity has colonized sever...</td>\n",
       "      <td>Title: Cowboy Bebop. Overview: In the year 207...</td>\n",
       "      <td>245</td>\n",
       "      <td>[0.00921056978404522, -0.012633174657821655, 0...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>5</td>\n",
       "      <td>Cowboy Bebop: Tengoku no Tobira</td>\n",
       "      <td>8.39</td>\n",
       "      <td>Action, Drama, Mystery, Sci-Fi, Space</td>\n",
       "      <td>other day, another bounty—such is the life of ...</td>\n",
       "      <td>Title: Cowboy Bebop: Tengoku no Tobira. Overvi...</td>\n",
       "      <td>199</td>\n",
       "      <td>[-0.008109764195978642, -0.028518257662653923,...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   MAL_ID                             Name Score  \\\n",
       "0       1                     Cowboy Bebop  8.78   \n",
       "1       5  Cowboy Bebop: Tengoku no Tobira  8.39   \n",
       "\n",
       "                                            Genres  \\\n",
       "0  Action, Adventure, Comedy, Drama, Sci-Fi, Space   \n",
       "1            Action, Drama, Mystery, Sci-Fi, Space   \n",
       "\n",
       "                                           sypnopsis  \\\n",
       "0  In the year 2071, humanity has colonized sever...   \n",
       "1  other day, another bounty—such is the life of ...   \n",
       "\n",
       "                                                text  n_tokens  \\\n",
       "0  Title: Cowboy Bebop. Overview: In the year 207...       245   \n",
       "1  Title: Cowboy Bebop: Tengoku no Tobira. Overvi...       199   \n",
       "\n",
       "                                              vector  \n",
       "0  [0.00921056978404522, -0.012633174657821655, 0...  \n",
       "1  [-0.008109764195978642, -0.028518257662653923,...  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "anime = pd.read_pickle('data/anime.pkl')\n",
    "\n",
    "anime.head(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Title: Cowboy Bebop. Overview: In the year 2071, humanity has colonized several of the planets and moons of the solar system leaving the now uninhabitable surface of planet Earth behind. The Inter Solar System Police attempts to keep peace in the galaxy, aided in part by outlaw bounty hunters, referred to as \"Cowboys.\" The ragtag team aboard the spaceship Bebop are two such individuals. Mellow and carefree Spike Spiegel is balanced by his boisterous, pragmatic partner Jet Black as the pair makes a living chasing bounties and collecting rewards. Thrown off course by the addition of new members that they meet in their travels—Ein, a genetically engineered, highly intelligent Welsh Corgi; femme fatale Faye Valentine, an enigmatic trickster with memory loss; and the strange computer whiz kid Edward Wong—the crew embarks on thrilling adventures that unravel each member\\'s dark and mysterious past little by little. Well-balanced with high density action and light-hearted comedy, Cowboy Bebop is a space Western classic and an homage to the smooth and improvised music it is named after. Genres: Action, Adventure, Comedy, Drama, Sci-Fi, Space'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "anime['text'][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import lancedb\n",
    "\n",
    "uri = \"dataset/sample-anime-lancedb\"\n",
    "db = lancedb.connect(uri)\n",
    "table = db.create_table(\"anime\", anime)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\vaalt\\AppData\\Local\\anaconda3\\lib\\site-packages\\langchain\\embeddings\\openai.py:214: UserWarning: WARNING! engine is not default parameter.\n",
      "                    engine was transferred to model_kwargs.\n",
      "                    Please confirm that engine is what you intended.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "from langchain.vectorstores import LanceDB\n",
    "from langchain.chains import RetrievalQA\n",
    "import os\n",
    "\n",
    "embeddings = OpenAIEmbeddings(engine=\"text-embedding-ada-002\", openai_api_key=openai.api_key)\n",
    "\n",
    "docsearch = LanceDB(connection = table, embedding = embeddings)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='Title: Marin X. Overview: Korean animated movie mixing Mecha with anti-communist themes. Genres: Action, Adventure, Mecha, Sci-Fi, Shounen', metadata={'MAL_ID': 16784, 'Name': 'Marin X', 'Score': 'Unknown', 'Genres': 'Action, Adventure, Mecha, Sci-Fi, Shounen', 'sypnopsis': 'Korean animated movie mixing Mecha with anti-communist themes.', 'n_tokens': 35, 'vector': array([-0.01003191,  0.00912034,  0.0071506 , ...,  0.01442947,\n",
       "        -0.00128262, -0.00605121], dtype=float32), '_distance': 0.3988204002380371})]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "query = \"I'm looking for an animated action movie. What could you suggest to me?\"\n",
    "docs = docsearch.similarity_search(query, k=1)\n",
    "docs\n",
    "# docs[0].page_content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "' You could watch Kaitouranma The Animation, Kikaider 01 The Animation, SMAnime, or De:vadasy.'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Import Azure OpenAI\n",
    "from langchain.llms import AzureOpenAI\n",
    "\n",
    "qa = RetrievalQA.from_chain_type(llm=AzureOpenAI(deployment_name=\"text-davinci-003\", \n",
    "model_name=\"text-davinci-003\", openai_api_key=openai_api_key, openai_api_version=openai_api_version), \n",
    "chain_type=\"stuff\", retriever=docsearch.as_retriever(), return_source_documents=True)\n",
    "\n",
    "query = \"I'm looking for an action anime. What could you suggest to me?\"\n",
    "result = qa({\"query\": query})\n",
    "result['result']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Document(page_content=\"Title: Kaitouranma The Animation. Overview: Shinjuro may be a little young to be the master of a swordsmanship school, but fate didn't give him a choice. Now his position and martial arts skill land him in the middle of serious trouble when the rogue samurai Mikage faces off against the Tokugawa government, and Shinjuro and the small group of swordsmen who train at the school must now protect the town from harm. However, the group won't be challenged until the Tokugawa house calls in a favor, and the young swordsman is forced to duel Mikage himself. (Source: AniDB) Genres: Action, Adventure, Martial Arts, Samurai\", metadata={'MAL_ID': 2483, 'Name': 'Kaitouranma The Animation', 'Score': '5.99', 'Genres': 'Action, Adventure, Martial Arts, Samurai', 'sypnopsis': \"Shinjuro may be a little young to be the master of a swordsmanship school, but fate didn't give him a choice. Now his position and martial arts skill land him in the middle of serious trouble when the rogue samurai Mikage faces off against the Tokugawa government, and Shinjuro and the small group of swordsmen who train at the school must now protect the town from harm. However, the group won't be challenged until the Tokugawa house calls in a favor, and the young swordsman is forced to duel Mikage himself. (Source: AniDB)\", 'n_tokens': 146, 'vector': array([-0.01823905,  0.00753973,  0.03045369, ..., -0.00741998,\n",
       "        0.01266601, -0.01191987], dtype=float32), '_distance': 0.35099881887435913})"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result['source_documents'][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': \"I'm looking for an anime with animals and an adventurous plot.\",\n",
       " 'result': ' Arashi no Yoru ni, Juuippiki no Neko to Ahoudori, Ookami wa Ookamida, and Daisetsusan no Yuusha Kibaou all feature animals and an adventurous plot.',\n",
       " 'source_documents': [Document(page_content='Title: Arashi no Yoru ni. Overview: story about a goat and a wolf who become friends on a stormy night, and how they overcome differences and hardships. (Source: ANN) Genres: Adventure, Comedy, Drama, Fantasy', metadata={'MAL_ID': 1961, 'Name': 'Arashi no Yoru ni', 'Score': '7.7', 'Genres': 'Adventure, Comedy, Drama, Fantasy', 'sypnopsis': 'story about a goat and a wolf who become friends on a stormy night, and how they overcome differences and hardships. (Source: ANN)', 'n_tokens': 50, 'vector': array([-0.02380494, -0.01213636,  0.00808658, ...,  0.01916177,\n",
       "          0.00842009,  0.00714668], dtype=float32), '_distance': 0.326760470867157}),\n",
       "  Document(page_content='Title: Juuippiki no Neko to Ahoudori. Overview: Eleven naughty cats on the run from the neighborhood police chief hear that a giant fish is nearby for the taking. They go on a hazardous quest find it, learning that they must work as a team to reach their goal. (Source: The Anime Encyclopedia) Genres: Kids, Adventure, Fantasy', metadata={'MAL_ID': 6072, 'Name': 'Juuippiki no Neko to Ahoudori', 'Score': 'Unknown', 'Genres': 'Kids, Adventure, Fantasy', 'sypnopsis': 'Eleven naughty cats on the run from the neighborhood police chief hear that a giant fish is nearby for the taking. They go on a hazardous quest find it, learning that they must work as a team to reach their goal. (Source: The Anime Encyclopedia)', 'n_tokens': 75, 'vector': array([ 0.00682038, -0.00232614,  0.0322321 , ...,  0.01126343,\n",
       "          0.00234172,  0.00424938], dtype=float32), '_distance': 0.32723164558410645}),\n",
       "  Document(page_content='Title: Ookami wa Ookamida. Overview: Village animals are at a loss what to do about the tyrannical wolf. The clever monkey proposes an idea. (Source: Japanese Animated Film Classics) Genres: Fantasy', metadata={'MAL_ID': 34957, 'Name': 'Ookami wa Ookamida', 'Score': '5.43', 'Genres': 'Fantasy', 'sypnopsis': 'Village animals are at a loss what to do about the tyrannical wolf. The clever monkey proposes an idea. (Source: Japanese Animated Film Classics)', 'n_tokens': 46, 'vector': array([ 0.00979256, -0.01184441,  0.02411153, ...,  0.02837376,\n",
       "          0.00285543, -0.00797847], dtype=float32), '_distance': 0.32929423451423645}),\n",
       "  Document(page_content='Title: Daisetsusan no Yuusha Kibaou. Overview: The conflicting fates of human beings and wild animals are depicted in a naturalistic setting. The main character of the story is Fang, who was born to a hunting dog and a circus-runaway European wolf. Although Fang was raised by a human family, he is a wild animal after all, and is destined to live amongst nature. The story reaches its climax when Fang returns from the circus and faces his foe, a giant brown bear which killed his family. (Source: AnimeNfo) Genres: Adventure, Drama', metadata={'MAL_ID': 6202, 'Name': 'Daisetsusan no Yuusha Kibaou', 'Score': '6.92', 'Genres': 'Adventure, Drama', 'sypnopsis': 'The conflicting fates of human beings and wild animals are depicted in a naturalistic setting. The main character of the story is Fang, who was born to a hunting dog and a circus-runaway European wolf. Although Fang was raised by a human family, he is a wild animal after all, and is destined to live amongst nature. The story reaches its climax when Fang returns from the circus and faces his foe, a giant brown bear which killed his family. (Source: AnimeNfo)', 'n_tokens': 121, 'vector': array([-0.00991253,  0.00148529,  0.02400066, ...,  0.02528965,\n",
       "         -0.00104674,  0.02390989], dtype=float32), '_distance': 0.32930710911750793})]}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_filtered = anime[anime['Genres'].apply(lambda x: 'Action' in x)]\n",
    "qa = RetrievalQA.from_chain_type(llm=AzureOpenAI(deployment_name=\"text-davinci-003\", \n",
    "model_name=\"text-davinci-003\", openai_api_key=openai_api_key, openai_api_version=openai_api_version), chain_type=\"stuff\", \n",
    "    retriever=docsearch.as_retriever(search_kwargs={'data': df_filtered}), return_source_documents=True)\n",
    "\n",
    "query = \"I'm looking for an anime with animals and an adventurous plot.\"\n",
    "result = qa({\"query\": query})\n",
    "result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prompt engineering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "1. Urikupen Kyuujo-tai: This adventure comedy follows a team of brave young animals that rescues others in peril. With a dog, a boar, a deer, a koala, a mouse, a seagull, and a lion, this show is sure to please those looking for an action anime featuring animals.\n",
      "\n",
      "2. Nekketsu Jinmen Inu: Life Is Movie: This parody follows a passionate human-faced dog NEET/would be detective in his adventures. Fans of action anime with animals are sure to be engaged by this mystery story.\n",
      "\n",
      "3. Daisetsusan no Yuusha Kibaou: The main character of this drama is Fang, who was born to a hunting dog and a circus-runaway European wolf. Fang returns from the circus to face his foe, a giant brown bear which killed his family, making this story a great pick for those looking for an action anime with animals.\n"
     ]
    }
   ],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "template = \"\"\"You are a movie recommender system that help users to find anime that match their preferences. \n",
    "Use the following pieces of context to answer the question at the end. \n",
    "For each question, suggest three anime, with a short description of the plot and the reason why the user migth like it.\n",
    "If you don't know the answer, just say that you don't know, don't try to make up an answer.\n",
    "\n",
    "{context}\n",
    "\n",
    "Question: {question}\n",
    "Your response:\"\"\"\n",
    "\n",
    "\n",
    "PROMPT = PromptTemplate(\n",
    "    template=template, input_variables=[\"context\", \"question\"])\n",
    "\n",
    "chain_type_kwargs = {\"prompt\": PROMPT}\n",
    "\n",
    "llm=AzureOpenAI(deployment_name=\"text-davinci-003\", \n",
    "model_name=\"text-davinci-003\", openai_api_key=openai_api_key, openai_api_version=openai_api_version)\n",
    "\n",
    "qa = RetrievalQA.from_chain_type(llm=llm, \n",
    "    chain_type=\"stuff\", \n",
    "    retriever=docsearch.as_retriever(),\n",
    "    return_source_documents=True, \n",
    "    chain_type_kwargs=chain_type_kwargs)\n",
    "\n",
    "query = \"I'm looking for an action anime with animals, any suggestions?\"\n",
    "result = qa({'query':query})\n",
    "print(result['result'])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "You are a movie recommender system that help users to find anime that match their preferences. \n",
      "Use the following pieces of context to answer the question at the end. \n",
      "For each question, take into account the context and the personal information provided by the user.\n",
      "If you don't know the answer, just say that you don't know, don't try to make up an answer.\n",
      "\n",
      "{context}\n",
      "This is what we know about the user, and you can use this information to better tune your research:\n",
      "Age: 18\n",
      "Gender: female\n",
      "Question: {question}\n",
      "Your response:\n"
     ]
    }
   ],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "template_prefix = \"\"\"You are a movie recommender system that help users to find anime that match their preferences. \n",
    "Use the following pieces of context to answer the question at the end. \n",
    "For each question, take into account the context and the personal information provided by the user.\n",
    "If you don't know the answer, just say that you don't know, don't try to make up an answer.\n",
    "\n",
    "{context}\"\"\"\n",
    "\n",
    "user_info = \"\"\"This is what we know about the user, and you can use this information to better tune your research:\n",
    "Age: {age}\n",
    "Gender: {gender}\"\"\"\n",
    "\n",
    "template_suffix= \"\"\"Question: {question}\n",
    "Your response:\"\"\"\n",
    "\n",
    "user_info = user_info.format(age = 18, gender = 'female')\n",
    "\n",
    "COMBINED_PROMPT = template_prefix +'\\n'+ user_info +'\\n'+ template_suffix\n",
    "print(COMBINED_PROMPT)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Based on the information you provided, I suggest Urikupen Kyuujo-tai. It is an adventure, comedy and kids anime about four young animals, a rabbit, squirrel, bear and penguin, who form a team to rescue others in peril. It is a limited broadcast show on some American local TV stations for the Japanese community. Another suggestion is Daisetsusan no Yuusha Kibaou, an adventure and drama anime about a wolf born to a hunting dog and European wolf. It follows Fang as he returns from the circus to face a giant brown bear that killed his family. Lastly, I suggest Ookami wa Ookamida, a fantasy anime about village animals struggling against a tyrannical wolf.\n"
     ]
    }
   ],
   "source": [
    "PROMPT = PromptTemplate(\n",
    "    template=COMBINED_PROMPT, input_variables=[\"context\", \"question\"])\n",
    "\n",
    "chain_type_kwargs = {\"prompt\": PROMPT}\n",
    "qa = RetrievalQA.from_chain_type(llm=llm, \n",
    "    chain_type=\"stuff\", \n",
    "    retriever=docsearch.as_retriever(),\n",
    "    return_source_documents=True, \n",
    "    chain_type_kwargs=chain_type_kwargs)\n",
    "\n",
    "query = \"I'm looking for an action anime with animals, any suggestions?\"\n",
    "result = qa({'query':query})\n",
    "print(result['result'])\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='Title: Urikupen Kyuujo-tai. Overview: Four young animals, rabbit Seitaro Usagi, squirrel Risu, bear Kuma, and penguin Penguin (U-Ri-Ku-Pen), are part of a team of brave young animals that rescues others in peril. Other team members included a dog, a boar, a deer, a koala, a mouse, a seagull, and a lion. The animals would win a prize for completing a mission, as would the viewers, who were encouraged to write in and guess which of the creatures would save the world by each Friday (a single mission stretched over a week of TV). Created by Mitsuru Kaneko, this show was given a limited broadcast on some American local TV stations for the Japanese community. (Source: The Anime Encyclopedia) Genres: Adventure, Comedy, Kids', metadata={'MAL_ID': 4598, 'Name': 'Urikupen Kyuujo-tai', 'Score': 'Unknown', 'Genres': 'Adventure, Comedy, Kids', 'sypnopsis': 'Four young animals, rabbit Seitaro Usagi, squirrel Risu, bear Kuma, and penguin Penguin (U-Ri-Ku-Pen), are part of a team of brave young animals that rescues others in peril. Other team members included a dog, a boar, a deer, a koala, a mouse, a seagull, and a lion. The animals would win a prize for completing a mission, as would the viewers, who were encouraged to write in and guess which of the creatures would save the world by each Friday (a single mission stretched over a week of TV). Created by Mitsuru Kaneko, this show was given a limited broadcast on some American local TV stations for the Japanese community. (Source: The Anime Encyclopedia)', 'n_tokens': 178, 'vector': array([-0.00295096, -0.00956655,  0.01999222, ...,  0.01487335,\n",
       "         0.00342526,  0.00220147], dtype=float32), '_distance': 0.31860217452049255}),\n",
       " Document(page_content='Title: Nekketsu Jinmen Inu: Life Is Movie. Overview: The \"Life Is Movie\" featuring indie animator Junichi Yamamoto and Flash animator Tokumaru Naoko reintroducing the Hidenori Takahashi voiced passionate human-faced dog NEET/would be detective will be released as OVA and online on the Bandai Channel later this summer. (Sourced: Crunchyroll) Genres: Parody, Comedy, Mystery', metadata={'MAL_ID': 25253, 'Name': 'Nekketsu Jinmen Inu: Life Is Movie', 'Score': 'Unknown', 'Genres': 'Parody, Comedy, Mystery', 'sypnopsis': 'The \"Life Is Movie\" featuring indie animator Junichi Yamamoto and Flash animator Tokumaru Naoko reintroducing the Hidenori Takahashi voiced passionate human-faced dog NEET/would be detective will be released as OVA and online on the Bandai Channel later this summer. (Sourced: Crunchyroll)', 'n_tokens': 93, 'vector': array([-0.01268616, -0.00663562,  0.02199182, ...,  0.00113419,\n",
       "         0.01318766, -0.00950069], dtype=float32), '_distance': 0.32972174882888794}),\n",
       " Document(page_content='Title: Daisetsusan no Yuusha Kibaou. Overview: The conflicting fates of human beings and wild animals are depicted in a naturalistic setting. The main character of the story is Fang, who was born to a hunting dog and a circus-runaway European wolf. Although Fang was raised by a human family, he is a wild animal after all, and is destined to live amongst nature. The story reaches its climax when Fang returns from the circus and faces his foe, a giant brown bear which killed his family. (Source: AnimeNfo) Genres: Adventure, Drama', metadata={'MAL_ID': 6202, 'Name': 'Daisetsusan no Yuusha Kibaou', 'Score': '6.92', 'Genres': 'Adventure, Drama', 'sypnopsis': 'The conflicting fates of human beings and wild animals are depicted in a naturalistic setting. The main character of the story is Fang, who was born to a hunting dog and a circus-runaway European wolf. Although Fang was raised by a human family, he is a wild animal after all, and is destined to live amongst nature. The story reaches its climax when Fang returns from the circus and faces his foe, a giant brown bear which killed his family. (Source: AnimeNfo)', 'n_tokens': 121, 'vector': array([-0.00991253,  0.00148529,  0.02400066, ...,  0.02528965,\n",
       "        -0.00104674,  0.02390989], dtype=float32), '_distance': 0.3318692743778229}),\n",
       " Document(page_content='Title: Ookami wa Ookamida. Overview: Village animals are at a loss what to do about the tyrannical wolf. The clever monkey proposes an idea. (Source: Japanese Animated Film Classics) Genres: Fantasy', metadata={'MAL_ID': 34957, 'Name': 'Ookami wa Ookamida', 'Score': '5.43', 'Genres': 'Fantasy', 'sypnopsis': 'Village animals are at a loss what to do about the tyrannical wolf. The clever monkey proposes an idea. (Source: Japanese Animated Film Classics)', 'n_tokens': 46, 'vector': array([ 0.00979256, -0.01184441,  0.02411153, ...,  0.02837376,\n",
       "         0.00285543, -0.00797847], dtype=float32), '_distance': 0.3326758146286011})]"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result['source_documents']"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
